package com.fansl.koala.quickdev.module.auth.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fansl.koala.quickdev.common.bean.entity.SendMailMessage;
import com.fansl.koala.quickdev.common.bean.po.SendMailMessagePo;
import com.fansl.koala.quickdev.common.bean.po.SysLoginPo;
import com.fansl.koala.quickdev.common.bean.po.SysUserRegisterPo;
import com.fansl.koala.quickdev.common.bean.vo.LoginVo;
import com.fansl.koala.quickdev.common.enums.*;
import com.fansl.koala.quickdev.common.exception.BizException;
import com.fansl.koala.quickdev.common.exception.CheckedException;
import com.fansl.koala.quickdev.common.exception.RegisterCheckedException;
import com.fansl.koala.quickdev.component.message.email.EmailMessageTemplateContext;
import com.fansl.koala.quickdev.component.message.email.service.MailService;
import com.fansl.koala.quickdev.module.auth.service.IAuthService;
import com.fansl.koala.quickdev.module.users.entity.SysUser;
import com.fansl.koala.quickdev.module.users.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author fansl
 * @Description: 权限相关-服务实现类
 * @date 2020/3/17 14:38
 */
@Slf4j
@Service
public class AuthServiceImpl implements IAuthService {
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private MailService mailService;

    /**
     * 系统用户注册
     *
     * @param param 注册信息
     * @return TRUE/FALSE
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean registerSysUser(SysUserRegisterPo param) {
        //验证手机号是否已经存在
        int countByPhoneCount = sysUserService.count(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getMobile, param.getMobile())
                .eq(SysUser::getDelFlag, DeleteFlagEnum.NOT_DELETE.getCode())
        );
        if (countByPhoneCount > 0) {
            throw new RegisterCheckedException("该手机号已经存在");
        }
        //验证邮箱账号是否已经存在
        int countByEmailCount = sysUserService.count(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getEmail, param.getEmail())
                .eq(SysUser::getDelFlag, DeleteFlagEnum.NOT_DELETE.getCode())
        );
        if (countByEmailCount > 0) {
            throw new RegisterCheckedException("该邮箱账户已经存在");
        }
        //生成密码盐
        String slat = RandomUtil.randomString(6);
        SysUser sysUser = new SysUser();
        sysUser.setEmail(param.getEmail())
                .setMobile(param.getMobile())
                .setNickname(param.getEmail())
                .setUsername(param.getEmail())
                .setPassword(SecureUtil.sha1(param.getPassword() + slat))
                .setSalt(slat)
                .setActivateCode(generateActivateCode())
                .setActivateFlag(ActivateFlagEnum.INACTIVATED.getCode())
                .setGender(GenderEnum.UNKNOWN.getCode())
                .setLockFlag(LockFlagEnum.UNLOCK.getCode())
                .setDelFlag(DeleteFlagEnum.NOT_DELETE.getCode())
                .setCreateTime(LocalDateTime.now());
        boolean result = sysUserService.save(sysUser);
        if (result) {
            //发送激活邮件
            SendMailMessagePo sendMailMessagePo = new SendMailMessagePo();
            sendMailMessagePo.setEmailMessageType(EmailMessageTypeEnum.ACCOUNT_ACTIVATION)
                    .setReceiver(param.getEmail());
            Map<String, Object> extendParam = new HashMap<>(2);
            extendParam.put("username", sysUser.getUsername());
            extendParam.put("code", sysUser.getActivateCode());
            sendMailMessagePo.setExtendParam(extendParam);
            try {
                EmailMessageTemplateContext accountActivationMessage = new EmailMessageTemplateContext(sendMailMessagePo);
                SendMailMessage sendMailMessage = accountActivationMessage.execute();
                mailService.sendMimeMail(sendMailMessage);
            } catch (Exception e) {
                log.error("desc:{},param:{}", "系统用户注册[发送激活邮件][异常]", JSONObject.toJSONString(sendMailMessagePo), e);
                throw new BizException(ResultEnum.SEND_EMAIL_ERROR.getMessage());
            }
        }
        return result;
    }

    /**
     * 系统用户账户激活
     *
     * @param username 用户账户
     * @param code     激活码
     * @return TRUE/FALSE
     */
    @Override
    public Boolean activateSysUser(String username, String code) {
        //TODO 激活邮件是否已经过期，过期则需要手动重新发送
        //ResultEnum.ACCOUNT_ACTIVATED_EXPIRED.getMessage()
        //激活账户是否存在
        SysUser sysUser = sysUserService.getByUsername(username);
        if (Objects.isNull(sysUser)) {
            throw new BizException(ResultEnum.ACCOUNT_NOT_FOUND);
        }
        //账户是否已激活
        if (ActivateFlagEnum.ACTIVATED.getCode().equals(sysUser.getActivateFlag())) {
            throw new BizException(ResultEnum.ACCOUNT_ACTIVATED);
        }
        //验证激活码是否正确
        if (!sysUser.getActivateCode().equals(code)) {
            throw new BizException(ResultEnum.ACCOUNT_ACTIVATED_ERROR);
        }
        return sysUserService.accountActivate(sysUser.getId());
    }

    /**
     * 系统用户登录
     *
     * @param param 登录参数
     * @return 登录结果
     */
    @Override
    public LoginVo sysLogin(SysLoginPo param) {
        //获取用户
        SysUser sysUser;
        if(StrUtil.isNotBlank(param.getUsername())){
            sysUser = sysUserService.getByUsername(param.getUsername());
        }else {
            sysUser = sysUserService.getByEmail(param.getEmail());
        }
        //账户是否存在
        if (Objects.isNull(sysUser)) {
            throw new CheckedException(ResultEnum.ACCOUNT_NOT_FOUND.getMessage());
        }
        //账户是否已经激活
        if (!ActivateFlagEnum.ACTIVATED.getCode().equals(sysUser.getActivateFlag())) {
            throw new CheckedException(ResultEnum.ACCOUNT_NOT_ACTIVATE.getMessage());
        }
        //账户是否已锁
        if (LockFlagEnum.LOCKED.getCode().equals(sysUser.getLockFlag())) {
            throw new CheckedException(ResultEnum.ACCOUNT_LOCKED.getMessage());
        }
        //密码是否正确
        if (!sysUser.getPassword().equals(SecureUtil.sha1(param.getPassword() + sysUser.getSalt()))) {
            throw new CheckedException(ResultEnum.PASSWORD_ERROR.getMessage());
        }
        String token = UUID.fastUUID().toString();
        return LoginVo.builder()
                .token(token)
                .build();
    }

    /**
     * 重新发送激活码到邮箱
     *
     * @param username 用户名
     * @return TRUE/FALSE
     */
    @Override
    public Boolean sysUserReactivate(String username) {
        //查询用户是否存在
        SysUser sysUser = sysUserService.getByUsername(username);
        if(sysUser==null){
            throw new BizException(ResultEnum.ACCOUNT_NOT_FOUND);
        }
        //是否已经被激活
        if(ActivateFlagEnum.ACTIVATED.getCode().equals(sysUser.getActivateFlag())){
            throw new BizException(ResultEnum.ACCOUNT_ACTIVATED);
        }
        // 重新生成激活码
        SysUser update = new SysUser();
        update.setId(sysUser.getId());
        update.setActivateFlag(ActivateFlagEnum.INACTIVATED.getCode());
        update.setActivateCode(generateActivateCode());
        boolean result = sysUserService.updateById(update);
        if (result) {
            //发送激活邮件
            SendMailMessagePo sendMailMessagePo = new SendMailMessagePo();
            sendMailMessagePo.setEmailMessageType(EmailMessageTypeEnum.ACCOUNT_ACTIVATION)
                    .setReceiver(sysUser.getEmail());
            Map<String, Object> extendParam = new HashMap<>(2);
            extendParam.put("username", sysUser.getUsername());
            extendParam.put("code", update.getActivateCode());
            sendMailMessagePo.setExtendParam(extendParam);
            try {
                EmailMessageTemplateContext accountActivationMessage = new EmailMessageTemplateContext(sendMailMessagePo);
                SendMailMessage sendMailMessage = accountActivationMessage.execute();
                mailService.sendMimeMail(sendMailMessage);
            } catch (Exception e) {
                log.error("desc:{},param:{}", "重新发送激活码[发送激活邮件][异常]", JSONObject.toJSONString(sendMailMessagePo), e);
                throw new BizException(ResultEnum.SEND_EMAIL_ERROR.getMessage());
            }
        }
        return result;
    }

    private String generateActivateCode(){
        return RandomUtil.randomString(6);
    }
}
